﻿// Lid_FileChecker.cpp: 实现文件
//
#include "StdAfx.h"
#include "lid_Global.h"
#include "lid_FileChecker.h"
#include "rawTextFile.h"

//////////////////////////////////////////////////////////////////////////
// namespace lid : file library with indexed ID.						//
//  一个根据配置对文件进行自动编号,管理的工具.							//
//////////////////////////////////////////////////////////////////////////
namespace lid
{
	static const CString kstr_underLine= _T("_");
	static const TCHAR   kchar_underLine = _T('_');
	static const CString kstr_dot= _T(".");

	void LidFileChecker::clearFileNodeList(FileNodePtrList* plist)
	{
		for(FileNodePtrListIter iter = plist->begin(); iter !=  plist->end(); ++iter)
		{
			FileNodeType* pData = (FileNodeType*)*iter;
			delete pData;
		}
		plist->clear();
	}

	BOOL LidFileChecker::isFileExcluded( CString & fname )
	{
		static const CString kstr_desktopIni = (_T("Desktop.ini"));
		if (fname == IniFileName)
		{
			return FALSE;
		}
		if (fname == kstr_desktopIni )
		{
			return FALSE;
		}
		if (kchar_underLine == fname.GetAt(0))
		{
			return FALSE;
		}
		return TRUE;
	}

	/*
	功能:
	根据规则，解析要处理的文件.
	*/
	void LidFileChecker::extractNonPrefixFileName(FileNodePtrList* plist)
	{
		//固定的组合; R ST 15 _ AT
		CString strFixPrefixCombo = _frenameRule.strPreFix+_frenameRule.strFirstGroup+_frenameRule.strYear
			+kstr_underLine+_frenameRule.strSubGroup+kstr_dot;
		_fileNamePrefix = strFixPrefixCombo;
		//检查是否已经启用了规则的前缀.
		//规则[固定的组合]####_数字到下划线。通过.
		int  prefixLength = strFixPrefixCombo.GetLength();
		int  idxTarUnderLine;
		//
		for(FileNodePtrListIter iter = plist->begin(); iter != plist->end(); ++iter)
		{
			FileNodeType* pData = (FileNodeType*)*iter;
			CString str2;
			idxTarUnderLine = -1;
			if (0 == pData->orginName.Find(strFixPrefixCombo)) //有前缀.
			{
				int  idxLength = pData->orginName.GetLength()-1;
				TCHAR cNextChar;
				for (int i = prefixLength; i<=idxLength ; i++)
				{
					cNextChar = pData->orginName.GetAt(i);
					if (_T('0') > cNextChar || cNextChar > _T('9'))
					{
						if ( cNextChar == kchar_underLine)
						{
							idxTarUnderLine = i;
							i = idxLength;
						}
						i = idxLength;
					}	
				}
			}
			if (-1 != idxTarUnderLine)
			{
				pData->nonPrefixName = pData->orginName.Mid(idxTarUnderLine+1);
			}
			else
			{
				pData->nonPrefixName = pData->orginName; // 没有完成解析，使用原有文件名.
			}
		}
		//解压完毕.
	}

	void LidFileChecker::SortByNonPrefixName()
	{
		_flist.sort(FileNode::strcmp_byNonPrefixNameLogicalAscend);
	}
	void LidFileChecker::SortByReGeneratedName()
	{
		_flist.sort(FileNode::strcmp_byNonPrefixNameLogicalAscend);
	}
	//对齐数字//
	void LidFileChecker::renameFileByRules_inRam()
	{
		static const CString kstr_underLine= _T("_");
		static const CString kstr_formatNum2Bit = _T("%02d_");
		static const CString kstr_formatNum3Bit = _T("%03d_");
		static const CString kstr_formatNum4Bit = _T("%04d_");
		static const CString kstr_formatNum5Bit = _T("%05d_");
		static const CString kstr_formatNum6Bit = _T("%06d_");
		///
		int  fileIdx = 1;
		int  nFind   = -1;
		CString strTag;
		CString strIDX;
		//////////////////////////////////////////////////////////////////////////
		int		fcont = _flist.size();
		CString AutoFormatNumLine;
		if (fcont<100)
		{
			AutoFormatNumLine = kstr_formatNum2Bit;
		}
		else if (fcont<1000)
		{
			AutoFormatNumLine = kstr_formatNum3Bit;
		}
		else if (fcont<10000)
		{
			AutoFormatNumLine = kstr_formatNum4Bit;
		}
		else
		{
			AfxMessageBox(_T("Too Many Files"));
			AutoFormatNumLine = kstr_formatNum5Bit;
		}
		//////////////////////////////////////////////////////////////////////////
		if ( _frenameRule.m_tagArray.GetSize()>0 )
		{
			for (int i = 0 ; i <_frenameRule.m_tagArray.GetSize(); i ++)
			{
				strTag = _frenameRule.m_tagArray.GetAt(i);
				for(FileNodePtrListIter iter = _flist.begin(); iter != _flist.end(); ++iter)
				{
					nFind = -1;
					FileNodeType* pData = (FileNodeType*)*iter;
					CString tmp = pData->nonPrefixName;
					tmp.MakeLower();
					strTag.MakeLower();
					nFind = tmp.Find(strTag);
					if (-1 != nFind) // 如果找到了就优先命名.
					{
						strIDX.Format(AutoFormatNumLine,fileIdx);
						pData->reAsignName = _fileNamePrefix+strIDX+pData->nonPrefixName;
						pData->isReAsigned = TRUE;
						fileIdx++;
					}
				}
			}
		}
		for(FileNodePtrListIter iter = _flist.begin(); iter != _flist.end(); ++iter)
		{
			FileNodeType* pData = (FileNodeType*)*iter;
			if (FALSE == pData->isReAsigned )
			{
				strIDX.Format(AutoFormatNumLine,fileIdx);
				pData->reAsignName = _fileNamePrefix+strIDX+pData->nonPrefixName;
				pData->isReAsigned = TRUE;
				fileIdx++;
			}
		}
		fileIdx = 1;
	}

	void LidFileChecker::renameFile_toDisk()
	{
		CString old_fPath;
		CString new_fPath;
		int	sta_RenameCnt;
		CString strInfo;
		sta_RenameCnt = 0;
		for(FileNodePtrListIter iter = _flist.begin(); iter != _flist.end(); ++iter)
		{
			FileNodeType* pData = (FileNodeType*)*iter;
			old_fPath = IniFileFolder+pData->orginName;
			new_fPath = IniFileFolder+pData->reAsignName;
			if (old_fPath != new_fPath)
			{
				sta_RenameCnt++;
				RenameFile((LPTSTR)(LPCTSTR)old_fPath,(LPTSTR)(LPCTSTR)new_fPath);
			}
		}
		strInfo.Format(_T("重命名个数%d"),sta_RenameCnt);
		AfxGetMainWnd()->SetWindowText(strInfo);
		//AfxMessageBox(strInfo);
	}

	int LidFileChecker::readLidIniSetFile( CString fpath )
	{
		static const CString kIniSectionName_tags = _T("tags");
		/////////////////////////////////////////////////
		bgIniOperation bgIni(fpath);
		//读取[set][rule]小节中的参数.
		bgIni.iReadString(_T("rules"),_T("Prefix"),this->_frenameRule.strPreFix);
		bgIni.iReadString(_T("rules"),_T("FirstGroup"),this->_frenameRule.strFirstGroup);
		bgIni.iReadString(_T("rules"),_T("Year"),this->_frenameRule.strYear);
		bgIni.iReadString(_T("rules"),_T("SubGroup"),this->_frenameRule.strSubGroup);
		this->_frenameRule.iSingleStart = bgIni.iReadInt32(_T("set"),_T("iSingleStart"),1);
		this->_frenameRule.iGroupStart  = bgIni.iReadInt32(_T("set"),_T("iGroupStart"),1000);
		//读取[tags]小节所有的key值. 和对应的Val值，并存放到rule.m_tagArray结构体中.
		CStringArray keyStrArray;
		int keyArraySize;
		CString nextTag;
		this->_frenameRule.m_tagArray.RemoveAll();
		bgIni.readAllKeys(keyStrArray,kIniSectionName_tags);
		keyArraySize = keyStrArray.GetSize();
		for (int i = 0; i < keyArraySize; i++)
		{
			bgIni.iReadString(kIniSectionName_tags,keyStrArray.GetAt(i),nextTag);
			this->_frenameRule.m_tagArray.Add(nextTag);
		}
		//

		CString strfolderPath;
		CString strIniFileName;
		splitFpath2_folder_fileFullName(fpath, strfolderPath,strIniFileName); //获取ini所在的文件夹.
		this->IniFileFolder = strfolderPath;
		this->IniFileName = strIniFileName;
		return TRUE;
	}

	int LidFileChecker::autoReindexFile( void )
	{
		vector<CString> AllFilesVector;
		getAllFilesNoHide(this->IniFileFolder,AllFilesVector); //获取文件中所有的文件.

		/************************************************************************/
		/*   获取所有待处理的文件
		* 需要排除掉特殊的配置文件.std::_Vector_const_iterator<std::_Vector_val<ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char> > >,std::allocator<ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char> > > > > >::operator!= 返回	false	bool

		需要排除掉用户设置的特殊文件.
		*/
		/************************************************************************/
		this->clearFileNodeList(&_flist);
		vector<CString>::iterator itor;
		CString  fname;
		for(itor = AllFilesVector.begin(); itor!=AllFilesVector.end(); itor++)
		{
			fname = (CString)*itor;
			if (this->isFileExcluded(fname))
			{
				lid::FileNodeType* pData = new lid::FileNodeType;
				pData->orginName = fname;
				this->_flist.push_back(pData);
			}
		}
		this->extractNonPrefixFileName(&_flist);
		this->SortByNonPrefixName();
		//调试用：
		// 1) 对未带后缀的文件，进行排序。 并在console控制台输出.
#if 0
		for(lid::FileNodePtrListIter iter = this->_flist.begin(); iter != this->_flist.end(); ++iter)
		{
			lid::FileNodeType* pData = (lid::FileNodeType*)*iter;
			OutputDebugString(pData->nonPrefixName);
			OutputDebugString(_T("\n"));
		}
#endif

		this->renameFileByRules_inRam();
		//调试用：
		// 1) 对重新编号&命名后的文件，进行排序。 并在console控制台输出.
#if 0
		this->SortByReGeneratedName();
		OutputDebugString(_T("=======================\n"));
		for(lid::FileNodePtrListIter iter = this->_flist.begin(); iter != this->_flist.end(); ++iter)
		{
			lid::FileNodeType* pData = (lid::FileNodeType*)*iter;
			OutputDebugString(pData->reAsignName);
			OutputDebugString(_T("\n"));
		}
#endif

		//file.Open(_T("D:\\out.txt"),CFile::modeCreate|CFile::modeWrite);
		//TCHAR fmt[1] ={0xFEFF,};
		////file.putString(&fmt[0]);
		//_putw(fmt[0],file._FILE);

		//for(lid::FileNodePtrListIter iter = this->_flist.begin(); iter != this->_flist.end(); ++iter)
		//{
		//	lid::FileNodeType* pData = (lid::FileNodeType*)*iter;
		//	file.putString(pData->reAsignName);
		//	file.linefeed();
		//}
		//file.flushToDisk();
		//AfxMessageBox(_T("sdf"),MB_OKCANCEL);
		this->renameFile_toDisk();
		return TRUE;
	}

	int LidFileChecker::detectPartialAdd( CString fpathSib )
	{
		//基地的处理//
		FileNodePtrList baseList;
		getRawNameToList( this->IniFileFolder,&baseList);
		extractNonPrefixFileName(&baseList);
		//子部的处理//
		FileNodePtrList partList;
		CString partfolderPath;
		CString partIniFileName;
		splitFpath2_folder_fileFullName(fpathSib, partfolderPath,partIniFileName); 
		getRawNameToList( partfolderPath,&partList);
		extractNonPrefixFileName(&partList);

		return 1;
	}

	int LidFileChecker::getRawNameToList( CString folder, FileNodePtrList* plist )
	{
		vector<CString> AllFilesVector;
		getAllFilesNoHide(folder,AllFilesVector); //获取基地文件中所有的文件.
		this->clearFileNodeList(plist);
		vector<CString>::iterator itor;
		CString  fname;
		for(itor = AllFilesVector.begin(); itor!=AllFilesVector.end(); itor++)
		{
			fname = (CString)*itor;
			if (this->isFileExcluded(fname))
			{
				lid::FileNodeType* pData = new lid::FileNodeType;
				pData->orginName = fname;
				plist->push_back(pData);
			}
		}
		return TRUE;
	}

	typedef int (WINAPI *pfnStrCmpLogical)(PCWSTR, PCWSTR);
	static HMODULE hShelllwapi = ::LoadLibrary(_T("Shlwapi.dll"));
	static pfnStrCmpLogical static_pfnStrCmpLogical = (pfnStrCmpLogical)::GetProcAddress(hShelllwapi, "StrCmpLogicalW");

	bool FileNode::strcmp_byNonPrefixNameLogicalAscend( FileNode* first, FileNode* second )
	{
		ASSERT(static_pfnStrCmpLogical);
		if( static_pfnStrCmpLogical(first->nonPrefixName, second->nonPrefixName) < 0 )
		{
			return TRUE;
		}
		else
		{
			return FALSE;
		}
	}

	bool FileNode::strcmp_byReAsignedNameLogicalAscend( FileNode* first, FileNode* second )
	{
		ASSERT(static_pfnStrCmpLogical);
		if( static_pfnStrCmpLogical(first->reAsignName, second->reAsignName) < 0 )
		{
			return TRUE;
		}
		else
		{
			return FALSE;
		}
	}
}